﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using Microsoft.Surface;
using Microsoft.Surface.Presentation;
using Microsoft.Surface.Presentation.Controls;
using System.Diagnostics;
using System.Windows.Forms;
using System.IO;
using System.Threading;
using System.Windows.Threading;
using System.Runtime.InteropServices;

namespace LetsGoToSchool
{
    /// <summary>
    /// Interaction logic for MockDialog.xaml
    /// Runs a real copy of openfiledialog off screen and 
    /// copy over the bitmap to the surface control. 
    /// Touch interactions are converted to corresponding 
    /// mouse events and are sended to the realy dialog.
    /// </summary>
    public partial class MockDialog : SurfaceUserControl
    {
        private Form _window;
        private DispatcherTimer _updateTimer;
        private ImageManager _imageManager;

        public MockDialog()
        {
            InitializeComponent();

            _updateTimer = new DispatcherTimer();
            _updateTimer.Interval = TimeSpan.FromSeconds(3);
            _updateTimer.Tick +=new EventHandler(_updateTimer_Tick);

            Contacts.AddPreviewContactDownHandler(_mock, MockWindowContactDown);
            Contacts.AddPreviewContactUpHandler(_mock, MockWindowContactUp);
        }

        public void setManager(ImageManager im)
        {
            _imageManager = im;
        }

        /// <summary>
        /// show the dialog as well as preparing the thread and the mock image
        /// </summary>
        public void Show()
        {
            Thread dialogThread = new Thread(DoWork);
            dialogThread.SetApartmentState(ApartmentState.STA);
            dialogThread.Start();
            _updateTimer.Start();
            this.Visibility = Visibility.Visible;
            (this.Parent as Grid).Visibility = Visibility.Visible;
        }

        /// <summary>
        /// the fisrt update takes longer, so we need to manually make it wait for a while.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void _updateTimer_Tick(object sender, EventArgs e)
        {
            _updateTimer.Stop();
            this.updateMock();
        }

        /// <summary>
        /// updates the bitmap
        /// </summary>
        public void updateMock()
        {
            _mock.Source = Utils.LoadImage(Utils.TakeSnapshot(new System.Drawing.Rectangle(1145, 28, 775, 546)));
            _mock.Width = _mock.Source.Width;
            _mock.Height = _mock.Source.Height;
            _mock.Stretch = Stretch.None;
        }

        /// <summary>
        /// send the corresponding mouse event and update the bitmap afterwards
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void MockWindowContactDown(object sender, ContactEventArgs e)
        {
            this.ProcessInkEvent(e.Contact.GetPosition(_mock), true, false);
            this.updateMock();
            e.Handled = true;
        }

        private void MockWindowContactUp(object sender, ContactEventArgs e)
        {
            this.ProcessInkEvent(e.Contact.GetPosition(_mock), false, true);
            this.updateMock();
        }

        /// <summary>
        /// call back and the real function of sending the mouse click to the real control at the corresponding position
        /// </summary>
        /// <param name="p"></param>
        /// <param name="sendDown"></param>
        /// <param name="sendUp"></param>
        delegate void ProcessInkEventCallback(Point p, bool sendDown, bool sendUp);
        private void ProcessInkEvent(Point p, bool sendDown, bool sendUp)
        {
            if (_window.InvokeRequired)
            {
                ProcessInkEventCallback d = new ProcessInkEventCallback(ProcessInkEvent);
                _window.Invoke(d, new object[] { p, sendDown, sendUp });
            }
            else
            {
                double wherex = p.X;
                double wherey = p.Y;
                //double wherex = p.X;
                //double wherey = p.Y;

                //still trying
                //http://msdn.microsoft.com/en-us/library/ms633497%28v=vs.85%29.aspx
                int where = ComSupport.MakeLParam((int)wherex - 168, (int)wherey - 94);
                IntPtr hwnd = _window.Handle;  // (IntPtr)0x110620;  //ComSupport.GetDesktopWindow();//
                //System.Windows.Forms.Cursor.Position = new System.Drawing.Point((int)wherex + 1145, (int)wherey + 28);
                //ComSupport.SendMessage(hwnd, ComSupport.WM_MOUSEMOVE, 0, where);
                if (sendDown)
                    ComSupport.SendMessage(hwnd, ComSupport.WM_LBUTTONDOWN, ComSupport.MK_LBUTTON, where);
                ComSupport.SendMessage(hwnd, ComSupport.WM_MOUSEMOVE, ComSupport.MK_LBUTTON, where);
                if (sendUp)
                    ComSupport.SendMessage(hwnd, ComSupport.WM_LBUTTONUP, 0, where);
                System.Windows.Forms.Cursor.Position = new System.Drawing.Point((int)wherex + 1145, (int)wherey + 28);
            }
        }

        public void Close()
        {
            //_window.Dispose();
        }

        /// <summary>
        /// close the dialog
        /// </summary>
        private void Hide()
        {
            this.Visibility = Visibility.Hidden;
            (this.Parent as Grid).Visibility = Visibility.Hidden;
        }

        /// <summary>
        /// callback function for threading
        /// </summary>
        delegate void HideCallback();

        /// <summary>
        /// open the dialog
        /// </summary>
        private void ShowDialog()
        {
            OpenFileDialog openFileDialog = new OpenFileDialog();

            openFileDialog.Multiselect = true;
            openFileDialog.CheckFileExists = true;
            openFileDialog.Filter = "All images (*.jpg; *.png; *.bmp)|*.jpg;*.png;*.bmp|All Files (*.*)|*.*";

            //create a dummy window to give an handle to the dialog and set the location
            _window = new Form();
            _window.StartPosition = FormStartPosition.Manual;
            _window.Location = new System.Drawing.Point(1144, 0);

            //the ui stuff belongs the the main thread, need to use call back to get the work done
            if (openFileDialog.ShowDialog(_window) == System.Windows.Forms.DialogResult.OK)
            {
                this.Dispatcher.Invoke(new LoadImagesCallback(_imageManager.ShowTypeBox), System.Windows.Threading.DispatcherPriority.Normal, new object[] { openFileDialog.FileNames });
            }
            else
            {
                this.Dispatcher.Invoke(new HideCallback(Hide), System.Windows.Threading.DispatcherPriority.Normal, new object[0]);
            }
            openFileDialog.Dispose();
        }

        /// <summary>
        /// callback function for threading
        /// </summary>
        delegate void LoadImagesCallback(string[] filePath);

        /// <summary>
        /// open the dialog in a new thread, because the call will block until the dialog is closed
        /// </summary>
        public void DoWork()
        {
            this.ShowDialog();
        }
    }
}